<?php

namespace app\worker\controller\kefu;

use think\App;
use Throwable;
use think\facade\Db;
use app\admin\model\kefu\User;
use GatewayWorker\Lib\Gateway;
use app\admin\model\kefu\Session;
use app\worker\library\kefu\Common;
use app\worker\library\WorkerWsApp;

/**
 * 客服 WebSocket session 控制器
 */
class Wsession
{
    /**
     * 客服系统配置
     */
    protected array $config = [];

    /**
     * 构造方法
     * @param WorkerWsApp $app 应用对象
     * @throws Throwable
     */
    public function __construct(protected App $app)
    {
        $configData = Db::name('kefu_config')->select();
        foreach ($configData as $item) {
            $this->config[$item['name']] = $item['value'];
        }

        $this->app->lang->load([
            app_path() . 'lang' . DIRECTORY_SEPARATOR . 'date.php',
        ]);
    }

    /**
     * 添加当前用户与某个用户的会话
     * @throws Throwable
     */
    public function addSession(): void
    {
        $kfUser          = Common::getUser();
        $sessionUserId   = $this->app->message['sessionUserId'] ?? 0;
        $sessionUserInfo = User::where('id', $sessionUserId)->find();

        if ($kfUser['identity'] != 'csr') {
            $this->app->send('error', [
                'message' => '您没有权限添加会话！',
                'code'    => 500,
            ]);
            return;
        }
        if (!$sessionUserInfo) {
            $this->app->send('error', [
                'message' => '用户找不到啦！',
                'code'    => 500,
            ]);
            return;
        }

        // 会话对象信息
        $sessionUserInfo = User::outputFields(['id', 'identity', 'avatar', 'nickname', 'status', 'last_login_time', 'create_time'], $sessionUserInfo);

        // 会话对象为访客
        if ($sessionUserInfo['identity'] != 'csr') {
            $session = Session::where('type', 'single')
                ->where('user_id', $sessionUserId)
                ->whereNull('delete_time')
                ->find();
            if ($session) {
                if ($session->session_user_id > 0 && $session->session_user_id != $kfUser['id']) {
                    $this->app->send('error', [
                        'message' => '用户已经被接待了~',
                        'code'    => 500,
                    ]);
                    return;
                }

                // 当前客服代表分配至会话
                $session->session_user_id = $kfUser['id'];
                $session->sort_time       = time();
                $session->save();
            }

            // 广播：访客已被接待
            $clientIds = Gateway::getClientIdByUid(Common::mark('uid', $sessionUserInfo));
            foreach ($clientIds as $clientId) {
                Gateway::leaveGroup($clientId, Common::mark('touristGroup'));
                Gateway::joinGroup($clientId, Common::mark('userGroup'));
            }
            Gateway::sendToGroup(Common::mark('csrGroup'), $this->app->assembleMessage('tourists', [
                'action' => 'reception',
                'user'   => $sessionUserInfo,
            ]));
        }

        // 会话对象为客服代表
        if ($sessionUserInfo['identity'] == 'csr') {
            // 检查是否已有会话
            $session = Session::where('type', 'single')
                ->whereRaw('(user_id=:uid1 AND session_user_id=:sid1) OR (user_id=:sid2 AND session_user_id=:uid2)', [
                    'uid1' => $kfUser['id'],
                    'sid1' => $sessionUserId,
                    'uid2' => $kfUser['id'],
                    'sid2' => $sessionUserId,
                ])
                ->whereNull('delete_time')
                ->find();
        }

        if (!isset($session) || !$session) {
            // 创建会话
            $session = Session::create([
                'user_id'         => $sessionUserId,
                'session_user_id' => $kfUser['id'], // 客服 id，固定写入到此字段
                'type'            => 'single',
                'sort_time'       => time(),
            ]);
        }

        // 会话信息整理
        $session = Common::formatSessionInfo($session, $kfUser['id']);

        $this->app->send('sessions', [
            'action'   => 'add',
            'sessions' => [$session],
        ], Common::mark('uid', $kfUser));
    }

    /**
     * 会话详情
     * @throws Throwable
     */
    public function sessionInfo(): void
    {
        Common::getSession($this->app->clientId);

        $id          = $this->app->message['id'] ?? 0;
        $readMessage = $this->app->message['readMessage'] ?? false;

        $session = Db::name('kefu_session')
            ->where('id', $id)
            ->whereNull('delete_time')
            ->find();
        if (!$session) {
            $this->app->send('error', [
                'message' => '会话找不到啦！',
                'code'    => 500,
            ]);
            return;
        }

        $kfUser = Common::getUser();

        // 会话信息
        $session         = Common::formatSessionInfo($session, $kfUser['id']);
        $sessionUserInfo = User::where('id', $session['session_user_id'])->find();

        // 标记当前会话消息已被阅读
        if ($readMessage) {
            Common::readMessage($id, $kfUser['id'], $session['session_user_id']);
        }

        $this->app->send('sessionInfo', [
            'sessionInfo'     => $session,
            'sessionUserInfo' => $sessionUserInfo,
        ]);
    }

    /**
     * 发送消息
     * @throws Throwable
     */
    public function sendSessionMessage(): void
    {
        $type      = $this->app->message['type'] ?? 'text';
        $content   = $this->app->message['content'] ?? '';
        $extend    = $this->app->message['extend'] ?? [];
        $sessionId = $this->app->message['session_id'] ?? 0;

        if (!$content) {
            $this->app->send('error', [
                'message' => '请输入消息内容！',
                'code'    => 500,
            ]);
            return;
        }

        $session = Db::name('kefu_session')
            ->where('id', $sessionId)
            ->whereNull('delete_time')
            ->find();
        if (!$session) {
            $this->app->send('error', [
                'message' => '会话找不到啦！',
                'code'    => 500,
            ]);
            return;
        }

        $kfUser      = Common::getUser();
        $message     = Common::sendSessionMessage($sessionId, $type, $content, $extend, $kfUser['id']);
        $recipientId = $session['user_id'] == $kfUser['id'] ? $session['session_user_id'] : $session['user_id'];

        if ($kfUser['identity'] != 'csr') {
            // 无客服用户，向所有客服代表广播：访客需接待
            if (!$recipientId) {
                Gateway::sendToGroup(Common::mark('csrGroup'), $this->app->assembleMessage('tourists', [
                    'action'        => 'await',
                    'message'       => $message,
                    'user'          => $kfUser,
                    'formatMessage' => Common::formatMessage($message),
                ]));

                if ($this->config['auto_response_user_id']) {
                    // 客服代表团队的在线情况 - 无法接待判定
                    $onlineCsrCount         = Db::name('kefu_user')
                        ->where('identity', 'csr')
                        ->where('status', 'online')
                        ->count();
                    $cannotReceptionContent = trim($this->config['cannot_reception_content']);
                    if ($cannotReceptionContent && !$onlineCsrCount) {
                        Common::sendSessionMessage($sessionId, 'text', $cannotReceptionContent, [], $this->config['auto_response_user_id']);
                        return;
                    }

                    // 游客初次进入排队流程 - 按需发送指定文案
                    $sessionUserMessage        = Db::name('kefu_message')
                        ->where('session_id', $sessionId)
                        ->where('sender_id', '<>', $kfUser['id'])
                        ->find();
                    $queuedAutoResponseContent = trim($this->config['queued_auto_response_content']);
                    if ($queuedAutoResponseContent && !$sessionUserMessage) {
                        Common::sendSessionMessage($sessionId, 'text', $queuedAutoResponseContent, [], $this->config['auto_response_user_id']);
                        return;
                    }
                }
            }

            // 知识库自动回复 - 仅限文本消息
            if ($this->config['kbs_auto_response_mode'] != 'close' && $type == 'text') {
                if ($recipientId) {
                    // 有客服代表
                    if ($this->config['kbs_auto_response_mode'] == 'csr_close') {
                        return;
                    }
                    $responseUser = $this->config['kbs_auto_response_mode'] == 'csr_auto_response_user' ? $this->config['auto_response_user_id'] : $recipientId;
                } else {
                    // 无客服代表
                    $responseUser = $this->config['auto_response_user_id'];
                }

                if (!empty($responseUser)) {
                    $bestKb = Common::getBestMatchKb($content);
                    if ($bestKb) {
                        Common::sendSessionMessage($sessionId, 'text', $bestKb['answer'], [
                            'id'    => $bestKb['id'],
                            'match' => $bestKb['match'], // 匹配度
                            'title' => $bestKb['title'], // 匹配的标题
                        ], $responseUser);
                    }
                }
            }
        }
    }

    /**
     * 阅读消息
     * @throws Throwable
     */
    public function readMessage(): void
    {
        Common::getSession($this->app->clientId);

        $senderId  = $this->app->message['senderId'] ?? 0;
        $sessionId = $this->app->message['sessionId'] ?? 0;

        if (!$sessionId || !$senderId) return;

        $kfUser = Common::getUser();
        Common::readMessage($sessionId, $kfUser['id'], $senderId);
    }

    /**
     * 会话的聊天记录
     * @throws Throwable
     */
    public function loadRecords(): void
    {
        Common::getSession($this->app->clientId);

        $id                = $this->app->message['id'] ?? 0;
        $page              = $this->app->message['page'] ?? 1;
        $size              = $this->app->message['size'] ?? 15;
        $unexpectedRecords = $this->app->message['unexpectedRecords'] ?? 0;

        if (!$id) {
            $this->app->send('error', [
                'message' => '会话找不到啦！',
                'code'    => 500,
            ]);
            return;
        }

        if ($page == 1) {
            $min = 0;
        } else {
            $min = ($page - 1) * $size;
            $min += $unexpectedRecords;
        }

        $kfUser = Common::getUser();
        list($messages, $users) = Common::loadRecords($id, $kfUser['id'], [
            'min'  => $min,
            'size' => $size,
        ]);
        $nextPage = count($messages) == $size;
        $messages = Common::groupByTime($messages);

        $this->app->send('sessionRecords', [
            'page'      => $page,
            'users'     => $users,
            'messages'  => $messages,
            'nextPage'  => $nextPage,
            'sessionId' => $id,
        ]);
    }

    /**
     * 搜索会话和用户
     * @throws Throwable
     */
    public function search(): void
    {
        $type    = $this->app->message['type'] ?? 'user';
        $keyword = $this->app->message['keyword'] ?? '';
        $page    = $this->app->message['page'] ?? 1;
        $size    = $this->app->message['size'] ?? 15;

        if (!$keyword) {
            $this->app->send('error', [
                'message' => '请输入关键词！',
                'code'    => 500,
            ]);
            return;
        }

        if ($page == 1) {
            $min = 0;
        } else {
            $min = ($page - 1) * $size;
        }

        $data  = [];
        $where = [];
        if ($type == 'user') {
            $where[] = [implode("|", ['user.id', 'user.nickname', 'sysUser.nickname', 'admin.nickname']), "LIKE", '%' . str_replace('%', '\%', $keyword) . '%'];
            $users   = User::withJoin(['sysUser', 'admin'], 'LEFT')
                ->where($where)
                ->order('user.create_time', 'desc')
                ->limit($min, $size)
                ->select();
            foreach ($users as $user) {
                $data[] = User::outputFields(['id', 'identity', 'avatar', 'nickname', 'remark', 'status', 'last_login_time'], $user);
            }
        } elseif ($type == 'session') {
            // 从会话中搜索用户
            $kfUser         = Common::getUser();
            $session        = Db::name('kefu_session')
                ->field('user_id,session_user_id')
                ->where('user_id|session_user_id', $kfUser['id'])
                ->whereNull('delete_time')
                ->order([
                    'sort_time'   => 'desc',
                    'create_time' => 'desc',
                ])
                ->select()
                ->toArray();
            $sessionUserIds = [];
            foreach ($session as $item) {
                $sessionUserIds[] = $item['user_id'] == $kfUser['id'] ? $item['session_user_id'] : $item['user_id'];
            }

            $where[] = [implode("|", ['user.id', 'user.nickname', 'sysUser.nickname', 'admin.nickname']), "LIKE", '%' . str_replace('%', '\%', $keyword) . '%'];
            $where[] = ['user.id', 'in', $sessionUserIds];
            $users   = User::withJoin(['sysUser', 'admin'], 'LEFT')
                ->where($where)
                ->limit($min, $size)
                ->select();
            foreach ($users as $user) {
                $data[] = User::outputFields(['id', 'identity', 'avatar', 'nickname', 'remark', 'status', 'last_login_time'], $user);
            }
        }

        $this->app->send('searchDone', [
            'type'     => $type,
            'data'     => $data,
            'page'     => $page,
            'nextPage' => count($data) == $size,
        ]);
    }

    /**
     * 会话列表（重新获取、刷新会话列表）
     * @throws Throwable
     */
    public function refreshSessionList(): void
    {
        $kfUser = Common::getUser();
        $this->app->send('sessions', [
            'action'   => 'refresh',
            'sessions' => Common::getSessions($kfUser['id']),
        ]);
    }

    /**
     * 会话操作
     * @throws Throwable
     */
    public function operates(): void
    {
        $id      = $this->app->message['id'] ?? 0;
        $operate = $this->app->message['operate'] ?? '';

        if (!$id || !$operate) {
            $this->app->send('error', [
                'message' => '参数错误！',
                'code'    => 500,
            ]);
            return;
        }

        $kfUser = Common::getUser();

        // 置顶会话
        if ($operate == 'top') {
            $exist = Db::name('kefu_session_top')
                ->where('user_id', $kfUser['id'])
                ->where('session_id', $id)
                ->value('top');
            if ($exist) {
                // 取消置顶
                Db::name('kefu_session_top')
                    ->where('user_id', $kfUser['id'])
                    ->where('session_id', $id)
                    ->delete();
            } else {
                Session::where('id', $id)->update([
                    'sort_time' => time(),
                ]);
                Db::name('kefu_session_top')->insert([
                    'user_id'    => $kfUser['id'],
                    'session_id' => $id,
                    'top'        => 1,
                ]);
            }
            $this->app->send('operates', [
                'id'      => $id,
                'status'  => !$exist,
                'operate' => $operate,
            ]);
            return;
        }

        // 删除会话
        if ($operate == 'remove') {
            Session::where('id', $id)->update([
                'delete_time' => time(),
            ]);
            $this->app->send('operates', [
                'id'      => $id,
                'operate' => $operate,
            ]);
            return;
        }

        // 邀请对话
        if ($operate == 'dialog-invite') {
            $this->app->send('operates', [
                'operate' => $operate,
            ], Common::mark('uid', [
                'id'       => $id,
                'identity' => 'tourist'
            ]));

            $this->app->send('tip', [
                'duration' => 3000,
                'type'     => 'success',
                'message'  => '邀请发送成功~',
            ]);

            Db::name('kefu_trajectory')
                ->insert([
                    'user_id'     => $id,
                    'title'       => '邀请对话',
                    'create_time' => time(),
                ]);
        }

        // 转移会话
        if ($operate == 'transfer') {
            $csrId = $this->app->message['csrId'] ?? 0;
            if (!$csrId) {
                $this->app->send('csrTransfer', [
                    'type'        => 'message',
                    'messageType' => 'error',
                    'message'     => '请选择正确的被转接客服！',
                ]);
                return;
            }

            $csrInfo = User::find($csrId);
            if (!$csrInfo) {
                $this->app->send('csrTransfer', [
                    'type'        => 'message',
                    'messageType' => 'error',
                    'message'     => '请选择正确的被转接客服！',
                ]);
                return;
            }

            $sessionInfo = Session::find($id);
            if (!$sessionInfo) {
                $this->app->send('csrTransfer', [
                    'type'        => 'message',
                    'messageType' => 'error',
                    'message'     => '会话找不到了！',
                ]);
                return;
            }

            $csrInfo = User::outputFields(['id', 'identity', 'avatar', 'nickname'], $csrInfo);

            if ($sessionInfo->session_user_id == $csrId) {
                $this->app->send('csrTransfer', [
                    'type'        => 'message',
                    'messageType' => 'error',
                    'message'     => "客服代表已经是 {$csrInfo['nickname']} 无需转接！",
                ]);
                return;
            }

            if ($sessionInfo->user_id == $csrId) {
                $this->app->send('csrTransfer', [
                    'type'        => 'message',
                    'messageType' => 'error',
                    'message'     => "客服代表不能是会话对象本身！",
                ]);
                return;
            }

            // 会话客服代表修改
            $sessionInfo->session_user_id = $csrId;
            $sessionInfo->save();

            // 发送系统消息
            Common::sendSessionMessage($id, 'system', "客服代表 {$csrInfo['nickname']} 接入", [], $sessionInfo->user_id);

            // 记录用户访问轨迹
            Db::name('kefu_trajectory')->insert([
                'user_id'     => $sessionInfo->user_id,
                'title'       => '客服代表转接',
                'create_time' => time(),
            ]);

            // 通知原客服代表删除会话
            $this->app->send('operates', [
                'id'      => $id,
                'operate' => 'remove',
            ]);
            $this->app->send('csrTransfer', [
                'id'   => $id,
                'type' => 'done',
            ]);
        }
    }
}